Skip to content

test(statement): cover null-typed bind parameter columns - #5

Closed
fornwall wants to merge 1 commit into
mainfrom
test/bind-null-typed
Closed

test(statement): cover null-typed bind parameter columns#5
fornwall wants to merge 1 commit into
mainfrom
test/bind-null-typed

Conversation

@fornwall

Copy link
Copy Markdown
Owner

Split out of #4 (one PR per test). Adds one generic, driver-agnostic test for a gap found while reviewing an ADBC driver (the adbc-spanner Rust driver) against this suite; candidate for upstreaming to adbc-drivers/validation later.

TestStatement.test_parameter_null_typed (gated on statement_bind)

Binds a batch whose parameter column has Arrow type null and asserts NULL is bound per row (insert + read-back through the existing sample_table fixture / its query_override hook).

  • Origin finding: adbc-spanner REVIEW.md CONV-1 (null-typed bind columns rejected, contradicting the driver's own get_parameter_schema).
  • Spec reference: AdbcStatementGetParameterSchema doc comment in adbc.h: "If the type cannot be determined, the type of the corresponding field will be NA (NullType)." A client that builds its bind batch from the driver's own reported parameter schema therefore produces null-typed columns; pyarrow also infers null for an all-None parameter set (the DBAPI executemany shape). A driver advertising bind support that rejects the type its own GetParameterSchema hands out contradicts itself.

Results on real drivers

  • adbc-spanner (current main): FAIL — verified by an actual emulator run via its foundry harness: INVALID_ARGUMENT: cannot bind parameter "p2": unsupported Arrow type Null.
  • adbc-driver-sqlite 1.11.0 (released PyPI wheel): PASS — verified with a throwaway quirks harness against a temp-file database, demonstrating the contract is satisfiable by an existing reference driver.

Framework checks

uv run pytest tests/ (210 passed, 1 skipped), uv run ty check (clean), pre-commit run --all-files (all hooks pass) — all on this branch independently.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LGf8PVEe2tYkw8Q6Pd95tq

fornwall added a commit to fornwall/adbc-spanner that referenced this pull request Jul 14, 2026
…a + accept Null-typed bind columns (#279)

* feat(statement): infer real parameter types in get_parameter_schema via a PLAN probe

get_parameter_schema used to type every @name parameter as Null, claiming
Spanner "exposes no way to introspect them beforehand". It does: a
QueryMode::Plan probe returns the statement's undeclared parameters in
ResultSetMetadata with the types the surrounding SQL implies (the same
mechanism PGAdapter uses for PostgreSQL Describe).

Queries plan in a single-use read-only transaction (the execute_schema
surface); DML can only be planned in a read/write transaction, so it runs
through the transaction runner - the plan executes nothing and the
transaction commits empty. Types map through the existing arrow_field
mapping, so a JSON parameter carries the arrow.json extension tag the bind
path understands. A parameter the probe cannot type - DDL, DML on a
read-only connection, a type the SQL context doesn't pin down, or a failed
probe - stays Null, ADBC's convention for "type cannot be determined"
(AdbcStatementGetParameterSchema in adbc.h).

Emulator-verified: undeclared_parameters comes back for both query and DML
plans; integration test now asserts Int64/Utf8 inference on both paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0192G976j7A1L8qFbfAJaU6N

* fix(bind): accept Null-typed bind parameter columns (CONV-1)

scalar_binder had no arm for Arrow's Null type, so a bind batch with a
Null-typed column failed InvalidArguments ("unsupported Arrow type Null") -
contradicting the driver's own get_parameter_schema, which types an
undetermined parameter Null per adbc.h's AdbcStatementGetParameterSchema
contract. A client building its bind batch from the reported schema (or
pyarrow inferring null for an all-None parameter set) hit the rejection.

Every cell of a Null-typed column now binds as an untyped NULL - the same
wire shape as a NULL cell of any typed column, since add_param declares no
parameter types and Spanner infers them from the SQL context. Not gated on
Array::is_null: a NullArray carries no validity buffer, so the physical
is_null reports false for its all-null cells.

Verified against the emulator (integration test inserts via a Null-typed
column and reads NULL back) and by the upstream validation suite's
test_parameter_null_typed (fornwall/validation#5), which fails on main and
passes with this fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0192G976j7A1L8qFbfAJaU6N

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@fornwall
fornwall force-pushed the test/bind-null-typed branch 2 times, most recently from b204b30 to 326f697 Compare July 14, 2026 09:49
Adds a test that binds a batch whose parameter column has Arrow type
null and asserts NULL is bound per row.

Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
@fornwall
fornwall force-pushed the test/bind-null-typed branch from 326f697 to e363d8e Compare July 14, 2026 09:50
@fornwall fornwall closed this Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant